# -*- coding: utf-8 -*-
# @Time : 2021/12/9 14:37
# @Author : Limusen
# @File : request_utils

import re
import json
import jsonpath
import requests
from faker import Faker
from requests.exceptions import ConnectionError
from requests.exceptions import ProxyError
from requests.exceptions import RequestException
from common.config_utils import local_config
from common.check_utils import CheckUtils
from common.logs_utils import logger

fake = Faker('zh_CN')


class RequestsUtils:

    def __init__(self):
        # 封装好的配置文件直接拿来用
        self.hosts = local_config.get_hosts
        # 全局session调用
        self.session = requests.session()
        self.temp_variables = {}

    def __get(self, request_info):
        """
        get请求封装
        :param request_info:
        :return:
        """
        try:
            # 　request_info 是我们封装好的数据，可以直接拿来用
            url = "https://%s%s" % (self.hosts, request_info["请求地址"])
            variables_list = re.findall('\\${.+?}', request_info["请求参数(get)"])
            for variable in variables_list:
                request_info["请求参数(get)"] = request_info["请求参数(get)"].replace(variable,
                                                                              self.temp_variables[variable[2:-1]])

            response = self.session.get(url=url,
                                        params=json.loads(request_info["请求参数(get)"]),
                                        # params=json.loads(
                                        #     requests_info['请求参数(get)'] if requests_info['请求参数(get)'] else None),
                                        headers=json.loads(request_info["请求头部信息"]) if request_info["请求头部信息"] else None
                                        )
            if request_info["取值方式"] == "正则取值":
                value_list = request_info['取值代码'].split(',')
                key_list = request_info['取值变量'].split(',')
                for index in range(0, len(value_list)):
                    # 如果总是抛错超出索引范围就需要查看，请查看正则表达式或者jsonpath取值模板是否有问题
                    # 这里需要注意的是 取出字符串数据,中间是没有空格的
                    # 例如"code":"100001"  正则模板应该为 "code":"(\d+)" 遇到数字请使用(\d+) 可以学习一下正则表达式提取
                    self.temp_variables[key_list[index]] = re.findall(value_list[index], response.text)[0]
            elif request_info["取值方式"] == "jsonpath取值":
                value_list = request_info['取值代码'].split(',')
                key_list = request_info['取值变量'].split(',')
                for index in range(0, len(value_list)):
                    self.temp_variables[key_list[index]] = jsonpath.jsonpath(response.json(), value_list[index])[0]

            variables_list = re.findall("\\${.+?}", request_info["期望结果"])
            for variable in variables_list:
                request_info["期望结果"] = request_info["期望结果"].replace(variable,
                                                                    self.temp_variables[variable[2:-1]])

            result = CheckUtils(response).run_check(request_info["断言类型"], request_info["期望结果"])
        except ProxyError as e:
            result = {"code": 3,
                      "error_message": "调用接口 [%s] 时发生连接异常，异常原因 [%s]" % (request_info["接口名称"], e.__str__()),
                      "check_result": False}
            logger.error("调用接口 {} 时发生异常，异常原因是: {}".format(request_info["接口名称"], e.__str__()))
        except ConnectionError as e:
            result = {"code": 3,
                      "error_message": "调用接口 [%s] 时发生连接异常，异常原因 [%s]" % (request_info["接口名称"], e.__str__()),
                      "check_result": False}
            logger.error("调用接口 {} 时发生异常，异常原因是: {}".format(request_info["接口名称"], e.__str__()))
        except RequestException as e:
            result = {"code": 3,
                      "error_message": "调用接口 [%s] 时发生请求异常，异常原因 [%s]" % (request_info["接口名称"], e.__str__()),
                      "check_result": False}
            logger.error("调用接口 {} 时发生异常，异常原因是: {}".format(request_info["接口名称"], e.__str__()))
        except Exception as e:
            result = {"code": 3,
                      "error_message": "调用接口 [%s] 时发生请求异常，异常原因 [%s]" % (request_info["接口名称"], e.__str__()),
                      "check_result": False}
            logger.error("调用接口 {} 时发生异常，异常原因是: {}".format(request_info["接口名称"], e.__str__()))
        return result

    def __post(self, request_info):
        """
        post请求封装
        :param request_info:
        :return:
        """
        try:
            url = "https://%s%s" % (self.hosts, request_info["请求地址"])
            variables_list = re.findall('\\${.+?}', request_info["请求参数(post)"])
            for variable in variables_list:
                request_info["请求参数(post)"] = request_info["请求参数(post)"].replace(variable,
                                                                                self.temp_variables[variable[2:-1]])
            # 新增的如果请求参数之中需要用到动态数据，则进行替换
            variables_list = re.findall('{{.+?}}', request_info['请求参数(post)'])
            for variable in variables_list:
                if variable == "{{rand_name}}":
                    request_info["请求参数(post)"] = request_info["请求参数(post)"].replace(variable, fake.name())
                elif variable == "{{rand_phone}}":
                    request_info["请求参数(post)"] = request_info["请求参数(post)"].replace(variable, fake.phone_number())
                elif variable == "{{rand_code}}":
                    # fake.random_number(digits=4) 生成长度为4的code
                    request_info["请求参数(post)"] = request_info["请求参数(post)"].replace(variable,
                                                                                    str(fake.random_number(
                                                                                        digits=4)))

            response = self.session.post(url=url,
                                         params=json.loads(request_info['请求参数(get)']),
                                         # params=json.loads(
                                         #     requests_info['请求参数(get)'] if requests_info['请求参数(get)'] else None),
                                         headers=json.loads(request_info["请求头部信息"]) if request_info["请求头部信息"] else None,
                                         json=json.loads(request_info["请求参数(post)"])
                                         )
            if request_info["取值方式"] == "正则取值":
                value_list = request_info['取值代码'].split(',')
                key_list = request_info['取值变量'].split(',')
                for index in range(0, len(value_list)):
                    # 如果总是抛错超出索引范围就需要查看，请查看正则表达式或者jsonpath取值模板是否有问题
                    # 这里需要注意的是 取出字符串数据,中间是没有空格的
                    # 例如"code":"100001"  正则模板应该为 "code":"(\d+)" 遇到数字请使用(\d+) 可以学习一下正则表达式提取
                    self.temp_variables[key_list[index]] = re.findall(value_list[index], response.text)[0]
            elif request_info["取值方式"] == "jsonpath取值":
                value_list = request_info['取值代码'].split(',')
                key_list = request_info['取值变量'].split(',')
                for index in range(0, len(value_list)):
                    self.temp_variables[key_list[index]] = jsonpath.jsonpath(response.json(), value_list[index])[0]

            variables_list = re.findall("\\${.+?}", request_info["期望结果"])
            for variable in variables_list:
                request_info["期望结果"] = request_info["期望结果"].replace(variable,
                                                                    self.temp_variables[variable[2:-1]])

            result = CheckUtils(response).run_check(request_info["断言类型"], request_info["期望结果"])
        except ProxyError as e:
            result = {"code": 3,
                      "error_message": "调用接口 [%s] 时发生连接异常，异常原因 [%s]" % (request_info["接口名称"], e.__str__()),
                      "check_result": False}
            logger.error("调用接口 {} 时发生异常，异常原因是: {}".format(request_info["接口名称"], e.__str__()))
        except ConnectionError as e:
            result = {"code": 3,
                      "error_message": "调用接口 [%s] 时发生连接异常，异常原因 [%s]" % (request_info["接口名称"], e.__str__()),
                      "check_result": False}
            logger.error("调用接口 {} 时发生异常，异常原因是: {}".format(request_info["接口名称"], e.__str__()))
        except RequestException as e:
            result = {"code": 3,
                      "error_message": "调用接口 [%s] 时发生请求异常，异常原因 [%s]" % (request_info["接口名称"], e.__str__()),
                      "check_result": False}
            logger.error("调用接口 {} 时发生异常，异常原因是: {}".format(request_info["接口名称"], e.__str__()))
        except Exception as e:
            result = {"code": 3,
                      "error_message": "调用接口 [%s] 时发生请求异常，异常原因 [%s]" % (request_info["接口名称"], e.__str__()),
                      "check_result": False}
            logger.error("调用接口 {} 时发生异常，异常原因是: {}".format(request_info["接口名称"], e.__str__()))
        return result

    def request(self, request_info):
        """
        封装方法自动执行post或者get方法
        :param request_info:
        :return:
        """
        request_type = request_info['请求方式']
        if request_type == "get":
            # 私有化方法,其他类均不可调用
            result = self.__get(request_info)
        elif request_type == "post":
            result = self.__post(request_info)
        else:
            result = {"code": 1, "error_message": "当前请求方式暂不支持!", "check_result": False}
        return result

    def request_steps(self, request_steps):
        """
        按照列表测试用例顺序执行测试用例
        :param request_steps:
        :return:
        """
        for request in request_steps:
            result = self.request(request)
            if result['code'] != 0:
                break
        return result


if __name__ == '__main__':
    requests_info = {'测试用例编号': 'api_case_03', '测试用例名称': '删除标签接口测试', '用例执行': '是', '用例步骤': 'step_01',
                     '接口名称': '获取access_token接口', '请求方式': 'get', '请求头部信息': '', '请求地址': '/cgi-bin/token',
                     '请求参数(get)': '{"grant_type":"client_credential","appid":"wxb637f897f0bf1f0d","secret":"501123d2d367b109a5cb9a9011d0f084"}',
                     '请求参数(post)': '', '取值方式': 'jsonpath取值', '取值代码': '$.access_token', '取值变量': 'token',
                     '断言类型': 'json_key', '期望结果': 'access_token,expires_in'}
    requests_info_post = {'测试用例编号': 'api_case_03', '测试用例名称': '删除标签接口测试', '用例执行': '是', '用例步骤': 'step_02',
                          '接口名称': '创建标签接口', '请求方式': 'post',
                          '请求头部信息': '', '请求地址': '/cgi-bin/tags/create',
                          '请求参数(get)': '{"access_token":"51_136b9lRBH4SdLbSYI9C_1Sf1OogELivPJPNZ5z1mTzekmp3Yg4XQn8mx-sb3WxxV99NRWAX5CQhVIF6-uY12H_nRDjmEJ7H7oEbz9-qNHWV1g04V2t-29pslCsiuaSxIrkUChv4a2rPwdhnEEMHeADAMUP"}',
                          '请求参数(post)': '{   "tag" : {     "name" : "snsnssn" } } ', '取值方式': '无',
                          '取值代码': '"id":(.+?),',
                          '取值变量': 'tag_id', '断言类型': 'none', '期望结果': ''}
    requests_info_list = [
        {'测试用例编号': 'api_case_03', '测试用例名称': '删除标签接口测试', '用例执行': '是', '用例步骤': 'step_01', '接口名称': '获取access_token接口',
         '请求方式': 'get', '请求头部信息': '', '请求地址': '/cgi-bin/token',
         '请求参数(get)': '{"grant_type":"client_credential","appid":"wxb637f897f0bf1f0d","secret":"501123d2d367b109a5cb9a9011d0f084"}',
         '请求参数(post)': '', '取值方式': 'jsonpath取值', '取值代码': '$.access_token', '取值变量': 'token_value', '断言类型': 'json_key',
         '期望结果': 'access_token,expires_in'},
        {'测试用例编号': 'api_case_03', '测试用例名称': '删除标签接口测试', '用例执行': '是', '用例步骤': 'step_02', '接口名称': '创建标签接口',
         '请求方式': 'post', '请求头部信息': '', '请求地址': '/cgi-bin/tags/create', '请求参数(get)': '{"access_token":"${token_value}"}',
         '请求参数(post)': '{   "tag" : {     "name" : "newtest" } } ', '取值方式': '无', '取值代码': '"id":(.+?),',
         '取值变量': 'tag_id', '断言类型': 'none', '期望结果': ''}
    ]

    res = RequestsUtils()
    # res.get(requests_info)
    # res.post(requests_info_post)
    print(res.request(requests_info_post))
    # print(res.request_steps(requests_info_list))
